<template>
    <div class="container">
        <h2>ref 示例</h2>
        <div class="section">
            <p>品牌：{{ car.name }}</p>
            <p>发布时间：{{ car.reportDate }}</p>
            <p>型号：{{ car.spec }}</p>
            <button @click="changeName">修改品牌</button>
        </div>

        <h2>reactive 示例</h2>
        <div class="section">
            <p>品牌：{{ carReactive.name }}</p>
            <p>发布时间：{{ carReactive.reportDate }}</p>
            <p>型号：{{ carReactive.spec }}</p>
            <button @click="changeReactiveName">修改品牌</button>
        </div>

        <h2>基本类型比较</h2>
        <div class="section">
            <p>ref 价格: {{ price }}</p>
            <p>普通变量 价格: {{ normalPrice }}</p>
            <button @click="changePrice">修改价格</button>
        </div>

        <h2>解构比较</h2>
        <div class="section">
            <p>解构后的 ref 品牌: {{ destructuredRefBrand }}</p>
            <p>解构后的 reactive 品牌: {{ destructuredReactiveBrand }}</p>
            <button @click="testDestructuring">测试解构</button>
        </div>
        <div class="games">
            <div v-for="game in games" :key="game.id">
                <ul>
                    <li>{{ game.name }}</li>
                </ul>
            </div>
            <button @click="games.push({ id: '004', name: '地下城与勇士' })">添加游戏</button>
            <button @click="games[0].name = '蛋仔'">修改第一个游戏</button>
        </div>
    </div>
</template>

<script lang="ts" setup>
/**
 * ref 和 reactive 的区别：
 * 
 * 1. 适用数据类型不同:
 *    - ref 可以包装任何类型的数据(基本类型和对象类型)
 *    - reactive 只能用于对象类型(对象、数组、Map、Set等)
 * 
 * 2. 访问和修改方式不同:
 *    - ref 创建的响应式数据，在 setup 中访问和修改需要通过 .value
 *    - reactive 创建的响应式数据可以直接访问和修改属性
 * 
 * 3. 解构行为不同:
 *    - ref 解构后仍然保持响应性(通过 .value 访问)
 *    - reactive 解构后会失去响应性
 * 
 * 4. 使用场景:
 *    - ref: 适合处理独立的基本类型数据或需要保持响应性的解构数据
 *    - reactive: 适合处理复杂的对象数据结构，且不需要解构使用
 */

import { ref, reactive, onMounted } from 'vue'

// 使用 ref 包装对象 - 需要通过 .value 访问和修改
const car = ref({
    name: '宝马',
    reportDate: '2020-01-01',
    spec: 'X5'
})

// 使用 reactive 直接创建响应式对象 - 可以直接访问和修改
const carReactive = reactive({
    name: '奥迪',
    reportDate: '2021-05-15',
    spec: 'Q7'
})

const games = reactive([
    { id: '001', name: '英雄联盟' },
    { id: '002', name: '王者荣耀' },
    { id: '003', name: '刺激战场' },
])

// ref 用于基本类型 - 这是 ref 的优势场景
const price = ref(500000)
// 普通变量 - 不具有响应性
let normalPrice = 500000

// 用于测试解构的变量
const destructuredRefBrand = ref('未解构')
let destructuredReactiveBrand = '未解构'

// ref 修改方法 - 需要通过 .value 访问
function changeName() {
    // 对象类型的 ref 需要通过 .value 访问，然后才能修改其属性
    car.value.name = '奔驰'
    car.value.spec = 'GLS500'
    console.log('使用 ref 修改后:', car.value)
}

// reactive 修改方法 - 直接修改属性
function changeReactiveName() {
    // reactive 对象可以直接修改属性，不需要 .value
    carReactive.name = '保时捷'
    carReactive.spec = 'Cayenne'
    console.log('使用 reactive 修改后:', carReactive)
}

// 修改基本类型值
function changePrice() {
    // ref 基本类型修改需要 .value
    price.value += 100000
    // 普通变量修改不会触发视图更新
    normalPrice += 100000
    console.log('普通变量价格(不会更新视图):', normalPrice)
}

// 测试解构
function testDestructuring() {
    // 从 ref 对象中解构
    const { name: refName } = car.value
    // 从 reactive 对象中解构
    const { name: reactiveName } = carReactive

    // 修改原始数据
    car.value.name = '解构后修改-' + Math.random().toString().slice(2, 6)
    carReactive.name = '解构后修改-' + Math.random().toString().slice(2, 6)

    // 显示解构后的数据 - ref 解构后的变量不会随原始数据变化
    destructuredRefBrand.value = refName
    // reactive 解构后的变量不会随原始数据变化
    destructuredReactiveBrand = reactiveName

    console.log('ref 解构值:', refName, '原始值:', car.value.name)
    console.log('reactive 解构值:', reactiveName, '原始值:', carReactive.name)
}

// 生命周期钩子中演示两种方式的使用
onMounted(() => {
    console.log('组件挂载完成')
    console.log('ref 对象需要通过 .value 访问:', car.value.name)
    console.log('reactive 对象可以直接访问:', carReactive.name)

    // 实际开发场景：从API获取数据后更新
    setTimeout(() => {
        // 模拟API请求返回数据
        const apiData = {
            name: 'API返回-兰博基尼',
            reportDate: '2023-01-01',
            spec: 'Urus'
        }

        // ref 方式更新整个对象
        car.value = apiData

        // reactive 方式更新属性
        Object.assign(carReactive, apiData)
    }, 2000)
})
</script>

<style scoped>
.container {
    padding: 20px;
    max-width: 800px;
    margin: 0 auto;
}

.section {
    border: 1px solid #ddd;
    padding: 15px;
    margin-bottom: 20px;
    border-radius: 5px;
    background-color: #f9f9f9;
}

button {
    background-color: #4CAF50;
    color: white;
    padding: 8px 15px;
    border: none;
    border-radius: 4px;
    cursor: pointer;
    margin-top: 10px;
}

button:hover {
    background-color: #45a049;
}

h2 {
    color: #333;
    border-bottom: 1px solid #eee;
    padding-bottom: 5px;
}
</style>